package com.example.voicepad.data;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.example.voicepad.model.Note;

public final class NoteDaoImpl extends SQLiteOpenHelper implements NoteDao {

	private Context context;

	public static final int DATABASE_VERSION = 1;
	public static final String DATABASE_NAME = "VoicePad.db";
	private static final String TYPE_TEXT = " TEXT";
	private static final String TYPE_INTEGER = " INTEGER";
	private static final String TYPE_DATE = " INTEGER";
	private static final String COMMA_SEP = ",";

	// @formatter:off
	private static final String SQL_CREATE_TABLE_NOTE = 
			"CREATE TABLE "
			+ VoicePadContract.Note.TABLE_NAME
			+ " (" 
			+ VoicePadContract.Note._ID + " INTEGER PRIMARY KEY,"
			+ VoicePadContract.Note.COLUMN_NAME_NOTE_CODE + TYPE_INTEGER + COMMA_SEP
			+ VoicePadContract.Note.COLUMN_NAME_NOTE_DATE + TYPE_DATE + COMMA_SEP
			+ VoicePadContract.Note.COLUMN_NAME_NOTE_CONTENT + TYPE_TEXT + COMMA_SEP
			+ VoicePadContract.Note.COLUMN_NAME_NOTE_IMPORTANT + TYPE_INTEGER
			+ " )";

	private static final String SQL_DELETE_TABLE_NOTE = 
			"DROP TABLE IF EXISTS "
			+ VoicePadContract.Note.TABLE_NAME;
	// @formatter:on

	private static NoteDaoImpl instance;

	private NoteDaoImpl(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}

	/**
	 * Retrieves the singleton instance. Receives a context which is used for database initialization but also stored
	 * for subsequent sql operation calls.
	 * 
	 * This method is thread-safe.
	 * 
	 * @return NoteDao with the instance.
	 */
	public static synchronized NoteDaoImpl getInstance(Context context) {
		if (instance == null) {
			instance = new NoteDaoImpl(context);
		}

		instance.setContext(context);
		
		return instance;
	}

	public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public void onCreate(SQLiteDatabase db) {
		db.execSQL(SQL_CREATE_TABLE_NOTE);
	}

	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// This database is only a cache for online data, so its upgrade policy is
		// to simply to discard the data and start over
		db.execSQL(SQL_DELETE_TABLE_NOTE);
		onCreate(db);
	}

	@Override
	public Long count() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Note select(Long id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Note> selectBetweenDates(Date from, Date to) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public List<Note> selectAll() {
		List<Note> result = new ArrayList<Note>();

		SQLiteDatabase db = NoteDaoImpl.getInstance(this.getContext()).getReadableDatabase();

		// Define a projection that specifies which columns from the database
		// you will actually use after this query.
		String[] projection = { VoicePadContract.Note._ID, VoicePadContract.Note.COLUMN_NAME_NOTE_CODE,
				VoicePadContract.Note.COLUMN_NAME_NOTE_DATE, VoicePadContract.Note.COLUMN_NAME_NOTE_CONTENT,
				VoicePadContract.Note.COLUMN_NAME_NOTE_IMPORTANT };

		String selection = null;
		String[] selectionArgs = null;

		// How you want the results sorted in the resulting Cursor
		String sortOrder = VoicePadContract.Note.COLUMN_NAME_NOTE_CODE + " DESC";

		Cursor cursor = db.query(VoicePadContract.Note.TABLE_NAME, // The table to query
				projection, // The columns to return
				selection, // The columns for the WHERE clause
				selectionArgs, // The values for the WHERE clause
				null, // don't group the rows
				null, // don't filter by row groups
				sortOrder // The sort order
				);

		while (cursor.moveToNext()) {
			Note note = this.retrieveNoteFromCursor(cursor);
			result.add(note);
		}

		return result;
	}

	public void persist(Note note) {

		// Gets the data repository in write mode
		SQLiteDatabase db = NoteDaoImpl.getInstance(this.getContext()).getWritableDatabase();

		// Create a new map of values, where column names are the keys
		ContentValues values = new ContentValues();
		values.put(VoicePadContract.Note.COLUMN_NAME_NOTE_CODE, note.getCode());
		values.put(VoicePadContract.Note.COLUMN_NAME_NOTE_DATE, note.getDate());
		values.put(VoicePadContract.Note.COLUMN_NAME_NOTE_CONTENT, note.getContent());
		values.put(VoicePadContract.Note.COLUMN_NAME_NOTE_IMPORTANT, note.getImportant());

		// Insert the new row, returning the primary key value of the new row
		long newRowId;
		newRowId = db.insert(VoicePadContract.Note.TABLE_NAME, null, values);

		System.out.println("Registros grabados en la base de datos: " + newRowId);

	}

	@Override
	public void delete(Long id) {

		// Gets the data repository in write mode
		SQLiteDatabase db = NoteDaoImpl.getInstance(this.getContext()).getWritableDatabase();

		String removeId = id.toString();
		
		int rowsDeleted = db.delete(VoicePadContract.Note.TABLE_NAME, VoicePadContract.Note._ID + "=?", new String[] { removeId });
		
		if (rowsDeleted != 1) {
			throw new RuntimeException("No se pudo eliminar el registro con id " + id);
		}

	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub

	}

	private Note retrieveNoteFromCursor(Cursor cursor) {
		Note note = new Note();

		Long id = cursor.getLong(cursor.getColumnIndexOrThrow(VoicePadContract.Note._ID));
		Long code = cursor.getLong(cursor.getColumnIndexOrThrow(VoicePadContract.Note.COLUMN_NAME_NOTE_CODE));
		Long date = cursor.getLong(cursor.getColumnIndexOrThrow(VoicePadContract.Note.COLUMN_NAME_NOTE_DATE));
		String content = cursor.getString(cursor.getColumnIndexOrThrow(VoicePadContract.Note.COLUMN_NAME_NOTE_CONTENT));
		Boolean important = (1 == cursor.getLong(cursor
				.getColumnIndexOrThrow(VoicePadContract.Note.COLUMN_NAME_NOTE_IMPORTANT)));

		note.setId(id);
		note.setCode(code);
		note.setDate(date);
		note.setContent(content);
		note.setImportant(important);

		System.out.println("Readed note: " + note);

		return note;
	}

}
